#include"ffaresampler.h"
#include"decoder/ffadecoder.h"


FFAResampler::FFAResampler()
{

}

FFAResampler::~FFAResampler()
{
    if(swrCtx){
        swr_free(&swrCtx);
    }
    if(srcPars){
        delete srcPars;
        srcPars = nullptr;
    }
    if(dstPars){
        delete dstPars;
        dstPars = nullptr;
    }

}

void FFAResampler::init(FFAudioPars *src_, FFAudioPars *dst_)
{
    srcPars = new FFAudioPars();
    memcpy(srcPars,src_,sizeof(FFAudioPars));

    dstPars = new FFAudioPars();
    memcpy(dstPars,dst_,sizeof(FFAudioPars));

    initSwr();
}

void FFAResampler::resample(AVFrame *srcFrame, AVFrame **dstFrame) {
    int maxNbSamples = swr_get_out_samples(swrCtx, srcFrame->nb_samples);

    *dstFrame = allocFrame(dstPars,maxNbSamples,srcFrame);
    int samples = swr_convert(
        swrCtx,
        (*dstFrame)->data,
        maxNbSamples,
        (const uint8_t **)srcFrame->data,
        srcFrame->nb_samples
    );
    if (samples < 0) {
        printError(samples);
        swr_free(&swrCtx);
        return;
    }

    if (!*dstFrame) {
        std::cerr << "av_frame_alloc error!" << std::endl;
        return;
    }

}

void FFAResampler::initSwr()
{
    swrCtx = swr_alloc_set_opts(swrCtx,
                                av_get_default_channel_layout(dstPars->nbChannels),dstPars->aFormatEnum,dstPars->sampleRate,
                                av_get_default_channel_layout(srcPars->nbChannels),srcPars->aFormatEnum,srcPars->sampleRate,
                                0,nullptr);

    if(!swrCtx){
        std::cerr << "initSwr error!" << std::endl;
        return;
    }

    int ret = swr_init(swrCtx);
    if(ret < 0 ){
        printError(ret);
        swr_free(&swrCtx);
        return;
    }

}

AVFrame* FFAResampler::allocFrame(FFAudioPars* aPars,int nbSamples,AVFrame* srcFrame)
{
    AVFrame* frame = av_frame_alloc();
    frame->format = aPars->aFormatEnum;
    frame->channels = aPars->nbChannels;
    frame->sample_rate = aPars->sampleRate;
    frame->channel_layout = av_get_default_channel_layout(aPars->nbChannels);
    frame->nb_samples = nbSamples;

    frame->pts = srcFrame->pts;

    int ret = av_frame_get_buffer(frame,0);
    if(ret < 0){
        printError(ret);
        av_frame_unref(frame);
        return nullptr;
    }


    return frame;
}

void FFAResampler::printError(int ret){
    char errorBuffer[AV_ERROR_MAX_STRING_SIZE];
    int res = av_strerror(ret,errorBuffer,sizeof errorBuffer);
    if(res < 0){
        std::cerr << "Unknow Error!" << std::endl;
    }
    else{
        std::cerr << "Error:" << errorBuffer << std::endl;
    }
}


